package com.miniserver.tql.database.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.miniserver.tql.database.DatabaseEngine;
import com.miniserver.tql.database.EngineContext;
import com.miniserver.tql.database.ModelConfiguration;
import com.miniserver.tql.database.Query;
import com.miniserver.tql.database.model.TAttr;
import com.miniserver.tql.database.model.TNode;
import com.miniserver.util.BussinessException;
import com.miniserver.util.LogUtil;
import com.miniserver.util.SolrQuery;
import com.miniserver.util.cache.MemCacheManager;

/**
 * 数据访问可以通过execute执行非数据库操作，<BR>
 * 数据交换通过values进行，粘合其他非数据库操作 <BR>
 * 如果执行出现错误，自动清理事务，返回错误提示
 * 
 * @see 目前DatabaseEngineBaseImpl是支持多线程并发的
 */
public class DatabaseEngineBaseImpl implements DatabaseEngine {
	protected static final LogUtil log = LogUtil.getLogUtil("DatabaseEngineBaseImpl");
	// protected SolrQuery solrQuery = new SolrQuery();
	public static final String SUCCESS = "{\"success\":true}";
	/** second */
	private static final long defaultCacheTimeOut = 600;

	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}

	@Override
	public String getTableName(EngineContext context, ResultSet rs) throws Exception {
		return rs.getMetaData().getTableName(1);
	}

	/**
	 * 开始事务
	 */
	@Override
	public void beginTrans(EngineContext context, TNode tNode) throws Exception {
		context.pushState(ConnectionState.DM_AUTO, ConnectionState.RC_WRITE);
		context.setHasTransaction(true);
		if (context.isMemdbMode()) {
			Connection[] conns = context.getMemdbConns();
			for (Connection conn : conns) {
				conn.setAutoCommit(false);
			}
		} else {
			Connection conn = context.getConnection();
			conn.setAutoCommit(false);
		}
		//
		context.put("@return", SUCCESS);
	}

	/**
	 * 提交事务
	 */
	@Override
	public void endTrans(EngineContext context, TNode tNode) throws Exception {
		context.pushState(ConnectionState.DM_AUTO, ConnectionState.RC_WRITE);
		context.setHasTransaction(true);
		if (context.isMemdbMode()) {
			Connection[] conns = context.getMemdbConns();
			for (Connection conn : conns) {
				conn.commit();
			}
		} else {
			Connection conn = context.getConnection();
			conn.commit();
		}
		//
		context.put("@return", SUCCESS);
	}

	/**
	 * 查询，可以动态添加查询参数
	 */
	@Override
	public void query(EngineContext context, TNode tQuery) throws Exception {
		context.pushState(ConnectionState.DM_AUTO, ConnectionState.RC_READ);
		Binder binder = SqlBuilder.prepareQuery(context, tQuery);
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			int paramIdx = 0;
			boolean paging = false;
			String sql = binder.getSql();
			TAttr pagination = tQuery.getAttribute("paging");
			if (pagination != null && pagination.getValue().equalsIgnoreCase("false")) {
				paging = false;
			} else {
				paging = true;
			}
			if (context.contains("?pageindex") && paging) {
				int pageIndex = Integer.parseInt(context.get("?pageindex"));
				int pageSize = 20;
				if (context.contains("?pagesize")) {
					pageSize = Integer.parseInt(context.get("?pagesize"));
				}
				sql = this.getPageSQL(binder.getSql(), pageSize, pageIndex);
			} else if (context.contains("?startindex") && paging) {
				int startIndex = Integer.parseInt(context.get("?startindex"));
				int querySize = 20;
				if (context.contains("?querysize")) {
					querySize = Integer.parseInt(context.get("?querysize"));
				}
				sql = this.getPresetSQL(binder.getSql(), startIndex, querySize);
			}
			//
			stmt = context.getConnection().prepareStatement(sql);
			for (String s : binder.getParams()) {
				bindParameter(stmt, ++paramIdx, Binder.paramValue(context, s));
			}
			rs = stmt.executeQuery();
			// 处理子节点
			long n = paging ? this.getRecordCount(context, binder) : 0;
			if (StringUtils.isNotBlank(context.get("@recordcount"))) {
				n = Math.max(n, Long.valueOf(context.get("@recordcount")));
			}
			Query query = new QueryImpl(this, context, rs, tQuery, n);
			query.run();
		} catch (Exception ex) {
			log.error("query: method:" + context.get("?m") + getStatementSQL(stmt, binder) + ex.getMessage());
			throw ex;
		} finally {
			if (rs != null) {
				rs.close();
			}
			if (stmt != null) {
				stmt.close();
			}
		}
	}

	/**
	 * 获取查询总的记录数量
	 * 
	 * @param conn
	 * @param sql
	 * @param bindStr
	 * @param likeSearchCols
	 * @param values
	 * @return
	 * @throws Exception
	 */
	protected long getRecordCount(EngineContext context, Binder binder) throws Exception {
		context.pushState(ConnectionState.DM_AUTO, ConnectionState.RC_READ);
		long recordCount = -1L;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			String recordCountSQL = String.format("select count(*) as mycount from (%s) as record", binder.getSql());
			stmt = context.getConnection().prepareStatement(recordCountSQL);
			int paramIdx = 0;
			for (String s : binder.getParams()) {
				if (StringUtils.isBlank(s)) {
					continue;
				}
				//
				bindParameter(stmt, ++paramIdx, Binder.paramValue(context, s));
			}
			rs = stmt.executeQuery();
			while (rs.next()) {
				recordCount = rs.getLong(1);
			}
		} catch (Exception ex) {
			log.error("getRecordCount" + getStatementSQL(stmt, binder) + ex.getMessage());
		} finally {
			if (rs != null)
				try {
					rs.close();
				} catch (SQLException e) {
				}
			if (stmt != null)
				try {
					stmt.close();
				} catch (SQLException e) {
				}
		}
		return recordCount;
	}

	private void doUpdate(EngineContext context, TNode tNode, Connection conn) throws Exception {
		Binder binder = SqlBuilder.prepareUpdate(context, tNode);
		PreparedStatement stmt = null;
		try {
			stmt = conn.prepareStatement(binder.getSql());
			int paramIdx = 0;
			for (String s : binder.getParams()) {
				if (StringUtils.isBlank(s)) {
					continue;
				}
				//
				bindParameter(stmt, ++paramIdx, Binder.paramValue(context, s));
			}

			if (stmt.executeUpdate() > 0) {
				context.put("@return", SUCCESS);
			} else {
				context.put("@return", "{\"success\":false}");
			}
		} catch (Exception e) {
			log.error("update:" + getStatementSQL(stmt, binder) + e.getMessage());
			if (context.get("?format").compareToIgnoreCase("xml") == 0) {
				context.put("@error_message", "<error_response><code>-1</code><msg>服务器内部错误</msg></error_response>");
			} else {
				context.put("@error_message", "{\"success\":false,\"code\":-1,\"msg\":\"服务器内部错误。\"}");
			}
			throw e;
		} finally {
			if (stmt != null)
				stmt.close();
		}
	}

	private void poolUpdate(EngineContext context, TNode tNode) throws Exception {
		context.pushState(ConnectionState.DM_MEMDB, ConnectionState.RC_WRITE);
		this.update(context, tNode);
		context.popState();
	}

	/**
	 * update 更新操作，可以动态添加insert /update中的field, update不支持添加where后的参数字段
	 */
	@Override
	public void update(EngineContext context, TNode tNode) throws Exception {
		context.pushState(ConnectionState.DM_AUTO, ConnectionState.RC_WRITE);
		if (context.isMemdbMode()) {
			Connection[] conns = context.getMemdbConns();
			for (Connection conn : conns) {
				this.doUpdate(context, tNode, conn);
			}
		} else {
			this.doUpdate(context, tNode, context.getConnection());
		}
	}

	/**
	 * 绑定参数，如果是like字段，添加'%'
	 * 
	 * @param stmt
	 * @param paramIdx
	 * @param value
	 * @param isLikeParameter
	 * @throws Exception
	 */
	public void bindParameter(PreparedStatement stmt, int paramIdx, String value) throws Exception {
		try {
			ParameterMetaData meta = stmt.getParameterMetaData();
			int type = meta.getParameterType(paramIdx);
			if (value != null && !value.equals("") && !value.equalsIgnoreCase("NULL")) {
				switch (type) {
				case Types.VARCHAR: {
					stmt.setString(paramIdx, value);
					break;
				}
				case Types.BIGINT: {
					stmt.setLong(paramIdx, Long.valueOf(value).longValue());
					break;
				}
				case Types.INTEGER: {
					stmt.setInt(paramIdx, Double.valueOf(value).intValue());
					break;
				}
				case Types.SMALLINT: {
					stmt.setInt(paramIdx, Double.valueOf(value).shortValue());
					break;
				}
				case Types.TIMESTAMP: {
					stmt.setTimestamp(paramIdx, new Timestamp(Long.valueOf(value)));
					break;
				}
				case Types.DOUBLE:
				case Types.NUMERIC: {
					stmt.setDouble(paramIdx, Double.valueOf(value));
					break;
				}
				case Types.BIT: {
					if (value.equalsIgnoreCase("true")) {
						stmt.setBoolean(paramIdx, true);
					} else if (value.equalsIgnoreCase("false")) {
						stmt.setBoolean(paramIdx, false);
					}
					break;
				}
				default: {
					stmt.setObject(paramIdx, value);
					break;
				}
				}

			} else {
				stmt.setNull(paramIdx, type);
			}
		} catch (Exception ex) {
			log.error("bindparameter: index" + String.valueOf(paramIdx) + getStatementSQL(stmt, null) + ex.getMessage());
			throw ex;
		}

	}

	/**
	 * 获取分页查询sql
	 * 
	 * @param queryString
	 * @param pageSize
	 * @param pageIndex
	 * @return
	 */
	protected String getPageSQL(String queryString, Integer pageSize, Integer pageIndex) {
		return queryString + " limit " + pageSize + " offset " + (pageIndex - 1) * pageSize;
	}

	/**
	 * 从给定位置查询一定条数的sql
	 * 
	 * @param queryString
	 * @param startIndex
	 *            起始的条目位置
	 * @param qeurySize
	 *            要查询的数量
	 */
	protected String getPresetSQL(String queryString, Integer startIndex, Integer querySize) {
		return queryString + " limit " + querySize + " offset " + (startIndex - 1);
	}

	/**
	 * ckeck 执行检查语句,与给定的结果相比,如果不相等,返回message-
	 */
	public void check(EngineContext context, TNode tNode) throws Exception {
		try {
			if (doCompare(context, tNode) != 0) {
				this.tthrow(context, tNode);
			}
		} catch (BussinessException ex) {
			throw ex;
		} catch (Exception ex) {
			log.error("check:" + ex.getMessage());
			throw ex;
		}
	}

	/**
	 * 比较数据和给定值是否相符
	 * 
	 * @param conn
	 * @param tNode
	 * @param values
	 * @return
	 */
	protected int doCompare(EngineContext context, TNode tNode) {
		TAttr tSrcAttr = tNode.getAttribute("value");
		if (tSrcAttr == null) {
			return 0;
		}
		//
		String srcValue = tSrcAttr.getValue();
		if (srcValue.startsWith("?") || srcValue.startsWith("@")) {
			srcValue = context.get(srcValue);
		}
		if (srcValue == null) {
			srcValue = "";
		}
		//
		TAttr tDestAttr = tNode.getAttribute("compareTo");
		if (tDestAttr == null) {
			return srcValue.compareTo("");
		}
		//
		String destValue = tDestAttr.getValue();
		if (destValue.startsWith("?") || destValue.startsWith("@")) {
			destValue = context.get(destValue);
		}
		if (destValue == null) {
			destValue = "";
		}
		//
		boolean asNumber = false;
		TAttr tAsNumber = tNode.getAttribute("asNumber");
		if (tAsNumber != null && tAsNumber.getValue().equalsIgnoreCase("true")) {
			asNumber = true;
		}
		//
		if (asNumber) {
			double src = Double.parseDouble(srcValue);
			double dest = Double.parseDouble(destValue);
			return Double.compare(src, dest);
		} else {
			return srcValue.compareTo(destValue);
		}
	}

	private boolean boolExpr(int intExpr, String operator) {
		String oper = operator.toLowerCase();
		switch (oper) {
		case "-1":
		case "lt":
			return intExpr < 0;
		case "lte":
			return intExpr <= 0;
		case "1":
		case "gt":
			return intExpr > 0;
		case "gte":
			return intExpr >= 0;
		case "ne":
		case "neq":
			return intExpr != 0;
		case "0":
		case "eq":
		default:
			return intExpr == 0;
		}
	}

	/**
	 * route 执行检查语句,与给定的结果相比,如果相等， 执行type=equal节点功能
	 */
	public void tif(EngineContext context, TNode tNode) throws Exception {
		try {
			int comareResult = doCompare(context, tNode);
			TNode[] list = tNode.getChildren();
			for (TNode child : list) {
				TAttr tCaseAttr = child.getAttribute("case");
				if (tCaseAttr == null) {
					tCaseAttr = child.getAttribute("type");
				}
				//
				if (tCaseAttr == null) {
					this.invoke(context, child);
					continue;
				}
				//
				String operator = tCaseAttr.getValue();
				if (operator.startsWith("?") || operator.startsWith("@")) {
					operator = context.get(operator);
				}

				if (operator == null) {
					operator = "eq";
				}
				//
				if (this.boolExpr(comareResult, operator)) {
					this.invoke(context, child);
					context.put("@return", this.getResult(context, child));
				}
			}
		} catch (BussinessException ex) {
			if (ex.isNeedLog() == true) {
				log.error("check" + ex.getMessage());
				ex.setNeedLog(false);
			}
			throw ex;
		} catch (Exception ex) {
			log.error("route" + ex.getMessage());
			throw ex;
		}
	}

	/**
	 * 根据获取传入的值,根据传入的值执行不同的操作
	 */
	@Override
	public void tswitch(EngineContext context, TNode tNode) throws Exception {
		try {
			String mapKey = "";
			TAttr tMapKeyAttr = tNode.getAttribute("value");
			if (tMapKeyAttr != null) {
				mapKey = tMapKeyAttr.getValue().toLowerCase();
			}
			//
			if (mapKey.startsWith("?") || mapKey.startsWith("@")) {
				mapKey = context.get(mapKey);
			}
			if (mapKey == null) {
				mapKey = "";
			}
			//
			TNode[] list = tNode.getChildren();
			for (TNode child : list) {
				TAttr tCaseAttr = child.getAttribute("case");
				if (tCaseAttr == null) {
					tCaseAttr = child.getAttribute("value");
				}
				//
				String childValue = tCaseAttr.getValue();
				if (childValue.startsWith("?") || childValue.startsWith("@")) {
					childValue = context.get(childValue);
				}
				if (childValue == null) {
					childValue = "";
				}
				//
				if (childValue.equalsIgnoreCase(mapKey)) {
					this.invoke(context, child);
					context.put("@return", this.getResult(context, child));
				}
			}
		} catch (Exception ex) {
			log.error("map" + ex.getMessage());
			throw ex;
		}
	}

	/**
	 * 根据模板配置生成新的查询语句,对query结果的每一行执行对应的操作，如子查询
	 */
	public void foreach(EngineContext context, TNode tNode, Query query) throws Exception {
		TNode[] funcNodes = tNode.getChildren();
		for (TNode tFunction : funcNodes) {
			String functionName = tFunction.getNodeName();
			if (functionName.equals("set")) {
				this.set(context, tFunction, query);
			} else if (functionName.equals("clone")) {
				this.clone(context, tFunction);
			} else {
				this.invoke(context, tFunction);
			}
		}
	}

	/**
	 * 从查询结果中设置参数供后续处理
	 */
	public void set(EngineContext context, TNode tVar, Query query) throws Exception {
		query.set(context, tVar);
	}

	/**
	 * 暂时保存一些中间结果到values中
	 * 
	 * @throws BussinessException
	 */
	public void clone(EngineContext context, TNode tClone) throws BussinessException {
		String to = (tClone.getAttribute("to")).getValue();
		if (!to.startsWith("@") && !to.startsWith("?")) {
			return;
		}
		//
		String fromValue;
		TAttr tDefaultValue = tClone.getAttribute("defaultValue");
		String fromExpr = (tClone.getAttribute("from")).getValue();
		// <clone from="?account$$location_1.lat" type="cache" to="@lat" />
		String type = "";
		if (tClone.getAttribute("clonetype") != null) {
			type = (tClone.getAttribute("clonetype")).getValue();
		}
		if (type.compareToIgnoreCase("cache") == 0) {
			StringBuffer keyBuffer = new StringBuffer();
			String[] vals = fromExpr.split("\\.");
			String[] keys = vals[0].split("\\$\\$");
			for (String key : keys) {
				if (key.startsWith("?") || key.startsWith("@")) {
					keyBuffer.append(context.get(key));
				} else {
					keyBuffer.append(key);
				}
			}
			fromValue = MemCacheManager.getValue(keyBuffer.toString(), vals[1]);
			if (StringUtils.isBlank(fromValue)) {
				if (tDefaultValue != null) {
					fromValue = tDefaultValue.getValue();
				} else
					throw new BussinessException("301", "获取缓存数据失败");
			}
		} else {
			if (tDefaultValue != null) {
				if (Binder.paramExists(context, fromExpr)) {
					fromValue = context.getFunction().eval(context, fromExpr);
				} else {
					fromValue = tDefaultValue.getValue();
				}
			} else {
				fromValue = context.getFunction().eval(context, fromExpr);
			}
		}
		context.put(to, fromValue);
	}

	private void defaultExecute(EngineContext context, TNode tNode) throws Exception {
		TNode[] list = tNode.getChildren();
		for (TNode child : list) {
			this.invoke(context, child);
		}
	}

	/**
	 * 执行一个自定义操作, 参数和结果通过values传递, 通过反射调用其他类，<BR>
	 * 需要的参数和返回的结果都存放在values中,<BR>
	 * 可以从node中读取配置的执行类，执行方法，和其他所需要的参数<BR>
	 * 
	 * 程序员指定一个Executor类, 替换引擎的默认行为(执行所有子节点),<BR>
	 */
	@Override
	public void execute(EngineContext context, TNode tNode) throws Exception {
		try {
			TAttr tClass = tNode.getAttribute("class");
			if (tClass == null) {
				this.defaultExecute(context, tNode);
				return;
			}
			//
			TAttr tMethod = tNode.getAttribute("method");
			if (tMethod == null) {
				this.defaultExecute(context, tNode);
				return;
			}
			//
			Class<?>[] parameterTypes = { DatabaseEngine.class, EngineContext.class, TNode.class };
			Class<?> cla = Class.forName(tClass.getValue());
			Method method = cla.getMethod(tMethod.getValue(), parameterTypes);
			method.invoke(cla.newInstance(), this, context, tNode);
		} catch (InvocationTargetException ite) {
			Throwable mainException = ite.getCause();
			// 处理业务异常 modified by ddl 2014-12-25
			if (mainException instanceof BussinessException) {
				mainException.printStackTrace();
				throw ((BussinessException) mainException);
			} else {
				ite.printStackTrace();
				throw ite;
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			log.error("执行任务失败" + ex.getMessage());
			throw ex;
		}
	}

	/**
	 * 反射执行本类中的方法
	 * 
	 * @param conn
	 * @param tFuncNode
	 * @param values
	 * @throws Exception
	 */
	@Override
	public void invoke(EngineContext context, TNode tFuncNode) throws Exception {
		// 为了提高效率, 使用【switch】替代【反射机制】
		String funcName = tFuncNode.getNodeName();
		switch (funcName) {
		case "query":
			this.query(context, tFuncNode);
			break;
		case "if":
		case "route": // 已过时, 建议使用if
			this.tif(context, tFuncNode);
			break;
		case "throw":
			this.tthrow(context, tFuncNode);
			break;
		case "update":
			this.update(context, tFuncNode);
			break;
		case "where":// SqlBuilder已处理过该节点
			break;
		case "execute":
			this.execute(context, tFuncNode);
			break;
		case "check": // 已过时, 建议使用if+throw
			this.check(context, tFuncNode);
			break;
		case "executeBackend":
			this.executeBackend(context, tFuncNode);
			break;
		case "solrQuery":
			(new SolrQuery()).query(context, tFuncNode);
			break;
		case "beginTrans":
			this.beginTrans(context, tFuncNode);
			break;
		case "endTrans":
			this.endTrans(context, tFuncNode);
			break;
		case "switch":
		case "map": // 已过时, 建议使用switch
			this.tswitch(context, tFuncNode);
			break;
		case "clone":
			this.clone(context, tFuncNode);
			break;
		case "executeMemdb":
			this.executeMemdb(context, tFuncNode);
			break;
		case "poolUpdate":// 已过时, 建议使用executeMemdb+update
			this.poolUpdate(context, tFuncNode);
			break;
		case "cache":
			this.cache(context, tFuncNode);
			break;
		default:
			Class<?>[] parameterTypes = { EngineContext.class, TNode.class };
			Method method = this.getClass().getMethod(funcName, parameterTypes);
			if (method != null) {
				method.invoke(this, context, tFuncNode);
			}
			break;
		}
	}

	/**
	 * 获取返回结果
	 * 
	 * @param tNode
	 * @param values
	 * @return
	 */
	protected String getResult(EngineContext context, TNode tNode) {
		TAttr tResult = tNode.getAttribute("result");
		String resultVarName = (tResult == null) ? "@return" : tResult.getValue();
		return context.get(resultVarName);
	}

	/**
	 * 获取最终的返回结果，优先输出错误结果
	 * 
	 * @param tNode
	 * @param values
	 * @return
	 */
	protected String getEndResult(TNode tNode, Map<String, String> values) {
		TAttr tResult = tNode.getAttribute("result");
		String resultVarName = (tResult == null) ? "@return" : tResult.getValue();
		if (values.get("@error_message") != null) {
			return values.get("@error_message");
		}
		String result = "";
		if (!resultVarName.equals("@return")) {
			result = "{\"data\":[{\"" + resultVarName + "\":\"" + values.get(resultVarName)
					+ "\"}],\"success\":\"true\"}";
		} else {
			result = values.get(resultVarName);
		}
		return result;
	}

	/**
	 * 执行模板中规定的操作，返回结果
	 */
	@Override
	public String handleRequest(ModelConfiguration modelConfig, Map<String, String> values) throws Exception {
		String methodName = values.get("?m");
		if (methodName == null || methodName.equals("")) {
			throw new Exception("Missing m paramter in URL.");
		}
		TNode tModel = modelConfig.get(methodName);
		if (tModel == null) {
			throw new Exception("Method [" + methodName + "] is undefined.");
		}
		// running
		EngineContext context = new EngineContextImpl(modelConfig, values, new EngineFunctionImpl());
		try {
			TNode[] funcNodes = tModel.getChildren();
			for (TNode tFunction : funcNodes) {
				if (tFunction.getNodeName().equals("clone")) {
					this.clone(context, tFunction);
				} else {
					this.invoke(context, tFunction);
				}
			}
		} catch (BussinessException ex) {
			if (ex.isNeedLog() == true) {
				log.error("handleRequest:" + methodName + ex.getMessage());
				ex.setNeedLog(false);
			}
			throw ex;
		} catch (Exception ex) {
			ex.printStackTrace();
			log.error("handleRequest:" + methodName + ex.getMessage());
			throw ex;
		} finally {
			context.destroy();
		}
		return this.getEndResult(tModel, values);
	}

	@Override
	public void executeMemdb(EngineContext context, TNode tNode) throws Exception {
		context.pushState(ConnectionState.DM_MEMDB, ConnectionState.RC_NONE);
		//
		TNode[] list = tNode.getChildren();
		for (TNode child : list) {
			this.invoke(context, child);
		}
		//
		context.popState();
	}

	@Override
	public void executeBackend(EngineContext context, TNode tNode) throws Exception {
		context.pushState(ConnectionState.DM_PHYSICAL, ConnectionState.RC_NONE);
		//
		TNode[] list = tNode.getChildren();
		for (TNode child : list) {
			this.invoke(context, child);
		}
		//
		context.popState();
	}

	@Override
	public void cache(EngineContext context, TNode tFuncNode) {
		StringBuffer keyBuffer = new StringBuffer();
		String[] vals = tFuncNode.getAttribute("key").getValue().split("\\$\\$");
		for (String val : vals) {
			if (val.startsWith("?") || val.startsWith("@")) {
				keyBuffer.append(context.get(val));
			} else {
				keyBuffer.append(val);
			}
		}
		TAttr tTimeout = tFuncNode.getAttribute("timeout");
		long timeout = defaultCacheTimeOut;
		if (tTimeout != null) {
			timeout = Long.valueOf((tTimeout).getValue());
		}
		HashMap<String, String> cacheInfo = new HashMap<String, String>();
		TNode[] childNodes = tFuncNode.getChildren();
		String nameStr = null;
		String valueStr = null;
		for (TNode tField : childNodes) {
			nameStr = tField.getAttribute("name").getValue();
			valueStr = tField.getAttribute("value").getValue();
			if (valueStr.indexOf("(") < 0) {
				if (valueStr.startsWith("?") || valueStr.startsWith("@")) {
					valueStr = context.get(valueStr);
				}
			} else {
				valueStr = context.getFunction().eval(context, valueStr);
			}
			cacheInfo.put(nameStr, valueStr);
		}
		MemCacheManager.put(keyBuffer.toString(), cacheInfo, timeout);
	}

	private String getStatementSQL(PreparedStatement stat, Binder binder) {
		/*
		 * if (stat == null) { if (binder == null) { return ""; } else { return
		 * "\n" + binder.getSql() + "\n" + binder.getParams(); } } String
		 * statementText = stat.toString(); return "\n" +
		 * statementText.substring(statementText.indexOf(": ") + 1);
		 */

		return "";
	}

	@Override
	public void tthrow(EngineContext context, TNode tNode) throws Exception {
		TAttr tMessage = tNode.getAttribute("message");
		if (tMessage == null) {
			tMessage = tNode.getAttribute("errorMessage");
		}
		TAttr tCode = tNode.getAttribute("code");
		if (tCode == null) {
			tCode = tNode.getAttribute("errorCode");
		}
		String code = (tCode == null) ? "1" : tCode.getValue();
		
		String message  = "检查失败";
		if(tMessage != null && tMessage.getValue() != null) {
			if (tMessage.getValue().startsWith("?") || tMessage.getValue().startsWith("@")) {
				message = context.get(tMessage.getValue());
			} else {
				message = tMessage.getValue();
			}
		}
		
		throw new BussinessException(code, message);
	}
}
